import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/common/prisma/PrismaService';
import { DeptDto } from '../dto/DeptDto';
import { plainToInstance } from 'class-transformer';
import DeptQueryParam from '../param/DeptQueryParam';
import PageResult from 'src/common/PageResult';

/*
 * @Author: jingfuu@163.com
 * @Date: 2024-11-12 14:23:29
 * @LastEditTime: 2024-11-27 13:48:09
 * @Description: 部门service
 */
@Injectable()
export class DeptService {
  constructor(private prisma: PrismaService) {}

  async getById(id: number): Promise<DeptDto> {
    const dept = this.prisma.sysDept.findUnique({
      where: {
        deptId: id,
      },
    });
    return plainToInstance(DeptDto, dept);
  }

  async getNormalById(id: number): Promise<DeptDto> {
    const dept = this.prisma.sysDept.findUnique({
      where: {
        deptId: id,
        status: '0',
      },
    });
    return plainToInstance(DeptDto, dept);
  }

  async getAllDept() {
    return await this.prisma.sysDept.findMany();
  }

  async list(param: DeptQueryParam): Promise<PageResult<DeptDto>> {
    const skip = param.pageNum != 0 ? (param.pageNum - 1) * param.pageSize : 0;
    const whereClause: any = this.generateDeptQueryCondition(param);
    const [total, depts] = await this.prisma.$transaction([
      this.prisma.sysDept.count({ where: whereClause }),
      this.prisma.sysDept.findMany({
        skip,
        take: param.pageSize,
        orderBy: {
          orderNum: 'asc',
        },
        where: whereClause,
      }),
    ]);
    const rows: DeptDto[] = plainToInstance(DeptDto, depts);
    return {
      total,
      rows,
    };
  }
  private generateDeptQueryCondition(param: DeptQueryParam): any {
    const whereClause: any = {};
    if (param.deptName) {
      whereClause.deptName = {
        contains: param.deptName,
      };
    }
    if (param.status) {
      whereClause.status = param.status;
    }
    return whereClause;
  }

  async getExcludeDepts(id: number): Promise<DeptDto[]> {
    const exCludeIds = [id];
    const children = await this.prisma.sysDept.findMany({
      where: {
        parentId: id,
      },
    });
    children.forEach((child) => {
      exCludeIds.push(child.deptId);
    });
    const sysDepts = await this.prisma.sysDept.findMany({
      orderBy: {
        createTime: 'desc',
      },
      where: {
        deptId: {
          notIn: exCludeIds,
        },
      },
    });
    return plainToInstance(DeptDto, sysDepts);
  }

  async updateDept(dept: DeptDto) {
    //基础信息修改
    await this.prisma.sysDept.update({
      where: {
        deptId: dept.deptId,
      },
      data: {
        parentId: dept.parentId,
        deptName: dept.deptName,
        leader: dept.leader,
        phone: dept.phone,
        email: dept.email,
        orderNum: dept.orderNum,
        status: dept.status,
      },
    });
    // 修改ancestors
    await this.updateAncestors(dept);
  }
  private async updateAncestors(dept: DeptDto) {
    //找出所有祖先节点
    const ancestorIds = [];
    await this.findAncestor(dept.parentId, ancestorIds);
    dept.ancestors = ancestorIds.join(',');
    await this.prisma.sysDept.update({
      where: {
        deptId: dept.deptId,
      },
      data: {
        ancestors: dept.ancestors,
      },
    });
    await this.prisma.sysDept.updateMany({
      where: {
        parentId: dept.deptId,
      },
      data: {
        ancestors: dept.ancestors + ',' + dept.deptId,
      },
    });
  }

  private async findAncestor(parentId: number, ancestorIds: number[]) {
    const parent = await this.getById(parentId);
    ancestorIds.unshift(parent.deptId);
    if (parent.parentId !== 0) {
      await this.findAncestor(parent.parentId, ancestorIds);
    }
  }
  async deleteDpet(id: number) {
    await this.prisma.sysDept.delete({ where: { deptId: id } });
  }

  async addDept(dept: DeptDto) {
    //基础信息修改
    const sysDept = await this.prisma.sysDept.create({
      data: {
        parentId: dept.parentId,
        deptName: dept.deptName,
        leader: dept.leader,
        phone: dept.phone,
        email: dept.email,
        orderNum: dept.orderNum,
        status: dept.status,
      },
    });
    // 修改ancestors
    await this.updateAncestors(plainToInstance(DeptDto, sysDept));
  }
}
